// Copyright [2022] <Tianyu Zhu, Shizhen Zhao, Zihang Ren>

#ifndef PULSE_H_
#define PULSE_H_

#include <functional>
#include <queue>
#include <vector>

#include "algorithm.h"
#include "graph.h"

class Pulse : public Algorithm {
 public:
    Pulse() {}
    ~Pulse();
    void SetupTopology(Graph* graph) override;
    Path FindPath(const Flow& flow) override;
    void print() const;

 private:
    struct Node {
        Node(NodeId id_in, int distance_in)
            : id(id_in), distance(distance_in) {}

        friend bool operator<(const Node &a, const Node &b) {
            return a.distance < b.distance;
        }
        friend bool operator>(const Node &a, const Node &b) {
            return a.distance > b.distance;
        }
        NodeId id;
        int distance;
    };

    struct PulseInfo {
        PulseInfo() {}
        void Clear() {
            min_cost_path.clear();
            min_delay_path.clear();
            random_rep_path.clear();
        }
        Path min_cost_path;
        Path min_delay_path;
        Path random_rep_path;
    };

    // Helper functions
    void Dijkstra(NodeId dst_node, bool flag, int* node_to_dst_dis);
    void Dfs(NodeId u, Path& path);
    bool check(NodeId u, int cost, int delay);
    bool update(NodeId u, const Path& path, double p);

    // Variables for initialization
    int* cost_map_;
    int* delay_map_;
    int num_nodes_;

    // Variables for pulse search
    bool* visited_;
    PulseInfo* info_;
    Flow flow_;
    int total_cost_;
    std::vector<Path> results_;
    int num_iterations_;
};

#endif  // PULSE_H_